package failover

import (
	"context"
	"errors"
	"fmt"
	"sync/atomic"
	"time"

	"gitee.com/flycash/ai-gateway-demo/internal/domain"
	"gitee.com/flycash/ai-gateway-demo/internal/service/llm"
	"github.com/ecodeclub/ekit/syncx"
)

const (
	// 连续失败阈值，达到此阈值后服务将被标记为不可用
	failureThreshold = 3
	// 服务恢复检查间隔
	recoveryCheckInterval = 10 * time.Second
)

// Service 使用已有的CurServiceProvider和ServiceGroup实现容错功能的服务
type Service struct {
	// 一个简单的映射关系，模型名字和对应的提供该模型服务的云服务商
	groups syncx.Map[string, *ServiceGroup]
}

// NewService 创建新的容灾服务
func NewService(serviceMap map[string][]llm.Service) *Service {
	s := &Service{
		groups: syncx.Map[string, *ServiceGroup]{},
	}

	// 初始化服务组
	for modelID, services := range serviceMap {
		group := &ServiceGroup{
			services: make([]*CurServiceProvider, len(services)),
			count:    &atomic.Int64{},
		}

		for i, svc := range services {
			group.services[i] = &CurServiceProvider{
				service: svc,
				cnt:     &atomic.Int32{},
			}
		}

		s.groups.Store(modelID, group)
	}

	// 启动恢复检查
	go s.startRecoveryChecker()

	return s
}

// startRecoveryChecker 启动定期恢复检查
func (s *Service) startRecoveryChecker() {
	ticker := time.NewTicker(recoveryCheckInterval)
	defer ticker.Stop()

	for range ticker.C {
		s.groups.Range(func(modelID string, group *ServiceGroup) bool {
			group.HealthyCheck()
			return true
		})
	}
}

// getModelIDFromRequest 从请求中获取模型ID
func (s *Service) getModelIDFromRequest(req domain.SyncRequest) string {
	if req.Model.RoutingType == "model" && req.Model.ModelID != "" {
		return req.Model.ModelID
	} else if req.Model.RoutingType == "provider" && req.Model.Provider != "" {
		return req.Model.Provider
	}
	return "default"
}

// SyncInvoke 实现同步调用并处理容错
func (s *Service) SyncInvoke(ctx context.Context, req domain.SyncRequest) (domain.SyncResponse, error) {
	model := s.getModelIDFromRequest(req)
	group, ok := s.groups.Load(model)
	if !ok {
		return domain.SyncResponse{}, errors.New("未知大模型")
	}

	provider, err := group.GetAvailableServices()
	if err != nil {
		return domain.SyncResponse{}, err
	}
	resp, err := provider.service.SyncInvoke(ctx, req)
	if err != nil {
		provider.MarkFailure()
	} else {
		provider.MarkSuccess()
	}
	return resp, err
}

// StreamInvoke 实现流式调用并处理容错
func (s *Service) StreamInvoke(ctx context.Context, req domain.SyncRequest) (chan domain.StreamEvent, error) {
	modelID := s.getModelIDFromRequest(req)

	// 获取服务组
	group, ok := s.groups.Load(modelID)
	if !ok {
		return nil, fmt.Errorf("no service group found for model: %s", modelID)
	}

	// 获取可用服务
	provider, err := group.GetAvailableServices()
	if err != nil {
		return nil, err
	}

	// 执行调用
	srcChan, err := provider.service.StreamInvoke(ctx, req)
	if err != nil {
		provider.MarkFailure()
		return nil, err
	}

	// 创建结果通道
	resultChan := make(chan domain.StreamEvent, 10)
	go func() {
		defer close(resultChan)
		errorOccurred := false

		for evt := range srcChan {
			// 检查错误
			if evt.Err != nil {
				errorOccurred = true
			}

			// 传递事件
			resultChan <- evt
		}
		if errorOccurred {
			provider.MarkFailure()
		} else {
			provider.MarkSuccess()
		}
	}()
	return resultChan, nil
}

// AsyncInvoke 实现异步调用并处理容错
func (s *Service) AsyncInvoke(ctx context.Context, req domain.AsyncRequest) (domain.AsyncResponse, error) {
	modelID := s.getModelIDFromRequest(req.Req)

	// 获取服务组
	group, ok := s.groups.Load(modelID)
	if !ok {
		return domain.AsyncResponse{}, fmt.Errorf("未知的大模型 %s", modelID)
	}
	// 获取可用服务
	provider, err := group.GetAvailableServices()
	if err != nil {
		return domain.AsyncResponse{}, err
	}
	// 执行调用
	resp, err := provider.service.AsyncInvoke(ctx, req)
	if err != nil {
		// 记录失败
		provider.MarkFailure()
		return domain.AsyncResponse{}, err
	}

	provider.MarkSuccess()
	return resp, nil
}
